﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BRM.DataAccess;
using BRM.DataObjects;
using System.IO;
using System.Collections;
using System.Data.SqlClient;
using Microsoft.SqlServer.Management;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Common;
using System.Security.Cryptography;
using System.Configuration;

namespace BRM.Business
{

    public class RestoreController
    {
        public delegate void DoProcess(string sFileName);
        public static event DoProcess DoProcessHandler;
        /// <summary>
        /// Hàm thực hiện quy trình restore
        /// </summary>
        /// <param name="sBkfilename">Tên file backup</param>
        /// <param name="sBkfilepath">Đường dẫn của file backup</param>
        /// <param name="sVersioninf">Version của file backup</param>
        /// <param name="vercol">Mảng chứa tất cả các file hay folder cần backup</param>
        /// <param name="sPass">Password của file backup</param>
        public void Restore(string sBkfilename, string sBkfilepath, string sVersioninf, ArrayList vercol, string sPass)
        {
            IOHelper iohelper = new IOHelper();
            //giải mã password
            string sDecrypt = Decrypt(sPass, true);
            //giải nén file
            iohelper.Decompress(sBkfilepath + "\\" + sBkfilename + ".zip", sBkfilepath, sDecrypt, false);
            iohelper.DoProcessHandler += new IOHelper.DoProcess(newIO_DoProcessHandler);
            VERSION ver = AQFramework.Utilities.Serializer<VERSION>.Load(sVersioninf);
            //đọc file info.xml và copy file từ thư mục vừa giải nén đến đường dẫn gốc
            foreach (versionItems item in ver.versions)
            {
                foreach (fileItems file in item.detail.files)
                {
                    foreach (string ai in vercol)
                    {
                        int a = ai.IndexOf('{');
                        int b = ai.Length - a - 2;
                        string sTemp = ai.Substring(a + 1, b);
                        FileInfo dNew = new FileInfo(sTemp);
                        if (dNew.Name == file.name && dNew.Extension == file.ext)
                        {
                            File.Copy(sBkfilepath + "\\" + sBkfilename + "\\" + file.name, sTemp, true);
                            if (DoProcessHandler != null)
                                DoProcessHandler(file.path);
                        }
                    }
                }
            }
            //đọc file info.xml và copy folder từ thư mục vừa giải nén đến đường dẫn gốc
            foreach (versionItems item in ver.versions)
            {
                foreach (folderItems folder in item.detail.folders)
                {
                    foreach (string sAi in vercol)
                    {
                        int a = sAi.IndexOf('{');
                        int b = sAi.Length - a - 2;
                        string sTemp = sAi.Substring(a + 1, b);
                        DirectoryInfo dNew = new DirectoryInfo(sTemp);
                        if (folder.name == dNew.Name)
                        {
                            DirectoryInfo source = new DirectoryInfo(sBkfilepath + "\\" + sBkfilename + "\\" + folder.name);
                            DirectoryInfo destination = new DirectoryInfo(sTemp);

                            iohelper.CopyAll(source, destination);
                            if (DoProcessHandler != null)
                                DoProcessHandler(folder.path);
                        }
                    }
                }
            }
            Directory.Delete(sBkfilepath + "\\" + sBkfilename, true);
        }

        void newIO_DoProcessHandler(string sFileName)
        {
            //throw new NotImplementedException();
            if (DoProcessHandler != null) DoProcessHandler(sFileName);
        }
        /// <summary>
        /// Hàm restore database
        /// </summary>
        /// <param name="sDbname">Tên database cần restore</param>
        /// <param name="filePath">Đường dẫn database khi restore</param>
        /// <param name="sServerName">Tên server</param>
        /// <param name="sUserName">Tên User</param>
        /// <param name="sPassword">Password user</param>
        /// <param name="sDataFilePath">Đường dẫn lưu file dữ liệu</param>
        /// <param name="sLogFilePath">Đường dẫn lưu file log</param>
        public void RestoreDatabase(String sDbname, String filePath, String sServerName, String sUserName, String sPassword, String sDataFilePath, String sLogFilePath)
        {

            Restore sqlRestore = new Restore();

            BackupDeviceItem deviceItem = new BackupDeviceItem(filePath, DeviceType.File);
            sqlRestore.Devices.Add(deviceItem);
            sqlRestore.Database = sDbname;
            //tạo kết nối với server
            ServerConnection connection = new ServerConnection(sServerName, sUserName, sPassword);
            Server sqlServer = new Server(connection);

            Database db = sqlServer.Databases[sDbname];
            sqlRestore.Action = RestoreActionType.Database;
            //lấy đường dẫn của file database .mdf
            String sDataFileLocation = sDataFilePath + sDbname + ".mdf";
            //láy đường dẫn của file _Log.ldf
            String sLogFileLocation = sLogFilePath + sDbname + "_Log.ldf";
            db = sqlServer.Databases[sDbname];
            RelocateFile rf = new RelocateFile(sDbname, sDataFileLocation);

            sqlRestore.RelocateFiles.Add(new RelocateFile(sDbname, sDataFileLocation));
            sqlRestore.RelocateFiles.Add(new RelocateFile(sDbname + "_log", sLogFileLocation));
            sqlRestore.ReplaceDatabase = true;
            sqlRestore.Complete += new ServerMessageEventHandler(sqlRestore_Complete);
            sqlRestore.PercentCompleteNotification = 10;
            sqlRestore.PercentComplete +=
               new PercentCompleteEventHandler(sqlRestore_PercentComplete);

            //tiến hành quá trình restore
            sqlRestore.SqlRestore(sqlServer);
            db = sqlServer.Databases[sDbname];
            db.SetOnline();
            sqlServer.Refresh();
            if (DoProcessHandler != null)
                DoProcessHandler(sDbname);
        }

        public event EventHandler<PercentCompleteEventArgs> PercentComplete;

        void sqlRestore_PercentComplete(object sender, PercentCompleteEventArgs e)
        {
            if (PercentComplete != null)
                PercentComplete(sender, e);
        }

        public event EventHandler<ServerMessageEventArgs> Complete;

        void sqlRestore_Complete(object sender, ServerMessageEventArgs e)
        {
            if (Complete != null)
                Complete(sender, e);
        }
        /// <summary>
        /// Hàm mã hóa chuỗi kí tự. Trả về giá trị mã hóa
        /// </summary>
        /// <param name="sCipherString">Tên chuỗi mã hóa</param>
        /// <param name="useHashing">Có sử dụng hashing để mã hóa dữ liệu; true là đúng, false là sai</param>
        /// <returns></returns>
        public string Decrypt(string sCipherString, bool useHashing)
        {
            byte[] keyArray;
            byte[] toEncryptArray = Convert.FromBase64String(sCipherString);

            System.Configuration.AppSettingsReader settingsReader = new AppSettingsReader();
            //Get your key from config file to open the lock!
            string sKey = (string)settingsReader.GetValue("SecurityKey", typeof(String));

            if (useHashing)
            {
                MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
                keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(sKey));
                hashmd5.Clear();
            }
            else
                keyArray = UTF8Encoding.UTF8.GetBytes(sKey);

            TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
            tdes.Key = keyArray;
            tdes.Mode = CipherMode.ECB;
            tdes.Padding = PaddingMode.PKCS7;

            ICryptoTransform cTransform = tdes.CreateDecryptor();
            byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

            tdes.Clear();
            return UTF8Encoding.UTF8.GetString(resultArray);
        }
    }
}

